namespace nwWCF
{
    using System;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Description;
    using System.ServiceModel.Dispatcher;

    /// <summary>
    /// Cyclic References Aware Attribute
    /// </summary>
    [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Method)]
    public class CyclicReferencesAwareAttribute :
        Attribute,
        IContractBehavior,
        IOperationBehavior
    {
        #region Private Fields

        /// <summary>
        /// 
        /// </summary>
        private readonly bool on = true;

        #endregion

        /// <summary>
        /// Initializes a new instance of the <see cref="CyclicReferencesAwareAttribute"/> class.
        /// </summary>
        /// <param name="on">if set to <c>true</c> [on].</param>
        public CyclicReferencesAwareAttribute(bool on)
        {
            this.on = on;
        }

        /// <summary>
        /// Gets a value indicating whether this <see cref="CyclicReferencesAwareAttribute"/> is on.
        /// </summary>
        /// <value><c>true</c> if on; otherwise, <c>false</c>.</value>
        public bool On
        {
            get { return this.on; }
        }

        #region IOperationBehavior Members

        /// <summary>
        /// Implement to pass data at runtime to bindings to support custom behavior.
        /// </summary>
        /// <param name="operationDescription">The operation being examined. Use for examination only. If the operation description is modified, the results are undefined.</param>
        /// <param name="bindingParameters">The collection of objects that binding elements require to support the behavior.</param>
        void IOperationBehavior.AddBindingParameters(
            OperationDescription operationDescription, 
            BindingParameterCollection bindingParameters)
        {
        }

        /// <summary>
        /// Implements a modification or extension of the client across an operation.
        /// </summary>
        /// <param name="operationDescription">The operation being examined. Use for examination only. If the operation description is modified, the results are undefined.</param>
        /// <param name="clientOperation">The run-time object that exposes customization properties for the operation described by <paramref name="operationDescription"/>.</param>
        void IOperationBehavior.ApplyClientBehavior(
            OperationDescription operationDescription, 
            ClientOperation clientOperation)
        {
            CyclicReferencesAwareContract.ReplaceDataContractSerializerOperationBehavior(
                operationDescription, 
                this.On);
        }

        /// <summary>
        /// Implements a modification or extension of the service across an operation.
        /// </summary>
        /// <param name="operationDescription">The operation being examined. Use for examination only. If the operation description is modified, the results are undefined.</param>
        /// <param name="dispatchOperation">The run-time object that exposes customization properties for the operation described by <paramref name="operationDescription"/>.</param>
        void IOperationBehavior.ApplyDispatchBehavior(
            OperationDescription operationDescription, 
            DispatchOperation dispatchOperation)
        {
            CyclicReferencesAwareContract.ReplaceDataContractSerializerOperationBehavior(
                operationDescription, 
                this.On);
        }

        /// <summary>
        /// Implement to confirm that the operation meets some intended criteria.
        /// </summary>
        /// <param name="operationDescription">The operation being examined. Use for examination only. If the operation description is modified, the results are undefined.</param>
        void IOperationBehavior.Validate(OperationDescription operationDescription)
        {
        }

        #endregion

        #region IContractBehavior Members

        /// <summary>
        /// Configures any binding elements to support the contract behavior.
        /// </summary>
        /// <param name="contractDescription">The contract description to modify.</param>
        /// <param name="endpoint">The endpoint to modify.</param>
        /// <param name="bindingParameters">The objects that binding elements require to support the behavior.</param>
        void IContractBehavior.AddBindingParameters(
            ContractDescription contractDescription, 
            ServiceEndpoint endpoint, 
            BindingParameterCollection bindingParameters)
        {
        }

        /// <summary>
        /// Implements a modification or extension of the client across a contract.
        /// </summary>
        /// <param name="contractDescription">The contract description for which the extension is intended.</param>
        /// <param name="endpoint">The endpoint.</param>
        /// <param name="clientRuntime">The client runtime.</param>
        void IContractBehavior.ApplyClientBehavior(
            ContractDescription contractDescription, 
            ServiceEndpoint endpoint, 
            ClientRuntime clientRuntime)
        {
            CyclicReferencesAwareContract.ReplaceDataContractSerializerOperationBehaviors(
                contractDescription, 
                this.On);
        }

        /// <summary>
        /// Implements a modification or extension of the client across a contract.
        /// </summary>
        /// <param name="contractDescription">The contract description to be modified.</param>
        /// <param name="endpoint">The endpoint that exposes the contract.</param>
        /// <param name="dispatchRuntime">The dispatch runtime that controls service execution.</param>
        void IContractBehavior.ApplyDispatchBehavior(
            ContractDescription contractDescription, 
            ServiceEndpoint endpoint, 
            DispatchRuntime dispatchRuntime)
        {
            CyclicReferencesAwareContract.ReplaceDataContractSerializerOperationBehaviors(
                contractDescription, 
                this.On);
        }

        /// <summary>
        /// Implement to confirm that the contract and endpoint can support the contract behavior.
        /// </summary>
        /// <param name="contractDescription">The contract to validate.</param>
        /// <param name="endpoint">The endpoint to validate.</param>
        void IContractBehavior.Validate(
            ContractDescription contractDescription, 
            ServiceEndpoint endpoint)
        {
        }

        #endregion
    }
}